/********************************************************************
	Rhapsody	: 8.4 
	Login		: kqbi
	Component	: iLPRServerComponent 
	Configuration 	: iLPRServerConfig
	Model Element	: iLPR_Server
//!	Generated Date	: Thu, 13, Feb 2020  
	File Path	: ../../server/iLPR_Server.cpp
*********************************************************************/

#include "FPM_Server.h"
//## package server

//## class iLPR_Server

#include "Common/Config.h"
#include "Utils/Logger.h"
#include "DBS/AbstractDb.h"
#include "DBS/MySqlDb.h"
#include "DBS/Store.h"
#include "Utils/Util.h"
#include "http/HttpServer.h"

FPM_Server::FPM_Server() : _abstractDb(0), _fsw(0), _httpServer(0), _lpr(0), _running(false), _store(0),
                           _curStaticImageFRSucceed(0) {
    //#[ operation iLPR_Server()
    //#]
}

FPM_Server::~FPM_Server() {
    //#[ operation ~iLPR_Server()
    if (_running) shutDown();
    //#]
}

void FPM_Server::cleanupObjects() {
    //#[ operation cleanupObjects()
    if (_httpServer)
        _httpServer.reset();
    _httpServer = 0;

    if (_fsw)
        _fsw.reset();
    _fsw = 0;

    if (_lpr)
        _lpr.reset();
    _lpr = 0;

    if (_store)
        _store.reset();
    _store = 0;

    if (_abstractDb)
        _abstractDb.reset();
    _abstractDb = 0;
    //#]
}

bool FPM_Server::createDatabaseStore() {
    //#[ operation createDatabaseStore()
#if 0
    _abstractDb = std::make_shared<MySqlDb>(Config::getInstance()->_dataBaseInfo.getDatabaseIp().c_str(),
                                            Config::getInstance()->_dataBaseInfo.getDatabaseUserName().c_str(),
                                            Config::getInstance()->_dataBaseInfo.getDatabasePassword().c_str(),
                                            Config::getInstance()->_dataBaseInfo.getDatabaseName().c_str(),
                                            Config::getInstance()->_dataBaseInfo.getDatabasePort());
    if (!_abstractDb->isSane()) {
        S_LOG_FATAL("Failed to open configuration database.");
        cleanupObjects();
        return false;
    }
    _store = std::make_shared<Store>(_abstractDb);
    S_LOG_DEBUG("iDAS_Server::createDatastore successs.");
#endif
    return true;
    //#]
}

bool FPM_Server::createFPM() {
    //#[ operation createFSW()
//    _fsw = std::make_shared<iLPR_FSW>(*this);
//    if (!_fsw->init(Config::getInstance()->_watchInfo.getWatchDir().c_str())) {
//        S_LOG_FATAL("Failed to createFSW.");
//        cleanupObjects();
//        return false;
//    }S_LOG_DEBUG("createFSW success.");
    std::cout << Config::getInstance()->_baseInfo.getAppId() << std::endl;
    std::cout << Config::getInstance()->_baseInfo.getSdkKey() << std::endl;
    std::cout << Config::getInstance()->_baseInfo.getActiveKey() << std::endl;
    MRESULT faceRes = _imageFaceEngine.ActiveSDK((char *) Config::getInstance()->_baseInfo.getAppId().c_str(),
                                                 (char *) Config::getInstance()->_baseInfo.getSdkKey().c_str(),
                                                 (char *) Config::getInstance()->_baseInfo.getActiveKey().c_str());
    printf("faceRes ============== %d\n", faceRes);
    if (faceRes) {
        S_LOG_FATAL("Failed to createFPM.");
        cleanupObjects();
        return false;
    }

    ASF_ActiveFileInfo activeFileInfo = {0};
    _imageFaceEngine.GetActiveFileInfo(activeFileInfo);

    faceRes = _imageFaceEngine.InitEngine(ASF_DETECT_MODE_IMAGE);//Image
    if (faceRes) {
        S_LOG_FATAL("Failed to createFPM.");
        cleanupObjects();
        return false;
    }
    loadThumbnailImages();
    return true;
    //#]
}

void FPM_Server::loadThumbnailImages() {
    std::vector<std::string> files;
    std::vector<std::string> images;
    GetAllFiles(files, Config::getInstance()->_baseInfo.getFilePath(), false);
    for (int i = 0; i < files.size(); ++i) {
        printf("file ================ %s\n", files.at(i).c_str());
        if (IsImageGDIPLUSValid(Config::getInstance()->_baseInfo.getFilePath() + "/" + files.at(i))) {
            images.push_back(Config::getInstance()->_baseInfo.getFilePath() + "/" + files.at(i));
            test(Config::getInstance()->_baseInfo.getFilePath() + "/" + files.at(i));
        }
    }
}

void FPM_Server::test1(std::vector<std::string> images) {
    for (int i = 0; i < images.size(); ++i) {
        IplImage *originImage = cvLoadImage(images.at(i).c_str());

        if (!originImage) {
            cvReleaseImage(&originImage);
            continue;
        }

        //FD
        ASF_SingleFaceInfo faceInfo = {0};
        MRESULT detectRes = _imageFaceEngine.PreDetectFace(originImage, faceInfo, true);
        if (MOK != detectRes) {
            cvReleaseImage(&originImage);
            continue;
        }

        //FR
        ASF_FaceFeature faceFeature = {0};
        faceFeature.featureSize = FACE_FEATURE_SIZE;
        faceFeature.feature = (MByte *) malloc(faceFeature.featureSize * sizeof(MByte));
        detectRes = _imageFaceEngine.PreExtractFeature(originImage, faceFeature, faceInfo);

        if (MOK != detectRes) {
            free(faceFeature.feature);
            cvReleaseImage(&originImage);
            continue;
        }
        _featuresVec.push_back(faceFeature);
    }
}

int FPM_Server::test(std::string path) {
    printf("test ---------------------------- \n");

    IplImage *image = cvLoadImage(path.c_str());
    if (!image) {
        cvReleaseImage(&image);
        return -1;
    }

//    if (m_curStaticImage)
//    {
//        cvReleaseImage(&m_curStaticImage);
//        m_curStaticImage = NULL;
//    }

    //  m_curStaticImage = cvCloneImage(image);
    // cvReleaseImage(&image);


    //FD
    ASF_SingleFaceInfo faceInfo = {0};
    MRESULT detectRes = _imageFaceEngine.PreDetectFace(image, faceInfo, true);

    //初始化
    //  m_curStaticShowAgeGenderString = "";
    //  m_curStaticShowCmpString = "";

    //  m_curFaceShowRect = Rect(0, 0, 0, 0);

    //  SendMessage(WM_PAINT);

    if (MOK == detectRes) {
        //show rect
//        int n_top = showRect.Height*faceInfo.faceRect.top / image->height;
//        int n_bottom = showRect.Height*faceInfo.faceRect.bottom / image->height;
//        int n_left = showRect.Width*faceInfo.faceRect.left / image->width;
//        int n_right = showRect.Width*faceInfo.faceRect.right / image->width;
//
//        m_curFaceShowRect.X = n_left + showRect.X;
//        m_curFaceShowRect.Y = n_top + showRect.Y;
//        m_curFaceShowRect.Width = n_right - n_left;
//        m_curFaceShowRect.Height = n_bottom - n_top;
//
//        //显示文字在图片左上角
//        m_curStringShowPosition.X = (REAL)(showRect.X);
//        m_curStringShowPosition.Y = (REAL)(showRect.Y);

        //age gender
        ASF_MultiFaceInfo multiFaceInfo = {0};
        multiFaceInfo.faceOrient = (MInt32 *) malloc(sizeof(MInt32));
        multiFaceInfo.faceRect = (MRECT *) malloc(sizeof(MRECT));

        multiFaceInfo.faceNum = 1;
        multiFaceInfo.faceOrient[0] = faceInfo.faceOrient;
        multiFaceInfo.faceRect[0] = faceInfo.faceRect;

        ASF_AgeInfo ageInfo = {0};
        ASF_GenderInfo genderInfo = {0};
        ASF_Face3DAngle angleInfo = {0};
        ASF_LivenessInfo liveNessInfo = {0};

        detectRes = _imageFaceEngine.FaceASFProcess(multiFaceInfo, image,
                                                    ageInfo, genderInfo, angleInfo, liveNessInfo);

        if (MOK == detectRes) {
            char test[50];
            sprintf(test, "age:%d,Gender:%s,living thing:%s", ageInfo.ageArray[0],
                    genderInfo.genderArray[0] == 0 ? "man" : "woman",
                    liveNessInfo.isLive[0] == 1 ? "yes" : "no");
            printf("test:%s\n", test);
        } else {
            // m_curStaticShowAgeGenderString = "";
        }

        //   SendMessage(WM_PAINT);

        free(multiFaceInfo.faceRect);
        free(multiFaceInfo.faceOrient);

        //FR
        detectRes = _imageFaceEngine.PreExtractFeature(image, _curStaticImageFeature, faceInfo);

        if (MOK == detectRes) {
            _curStaticImageFRSucceed = true;
        } else {
            _curStaticImageFRSucceed = false;
            //  CString resStr;
            //  resStr.Format("特征提取失败");
            printf("Feature extraction failed\n");
            // EditOut(resStr, TRUE);
            return -1;
        }
        return 0;
    } else {
        _curStaticImageFRSucceed = false;
        printf("No face detected\n");
        return -1;
    }
}

void FPM_Server::Compare() {
    if (!_curStaticImageFRSucceed) {
        printf("failed------------");
        return;
    }

    if (_featuresVec.size() == 0) {
        printf("failed++++++++++");
        return;
    }

    int maxIndex = 1;
    MFloat maxThreshold = 0.0;
    int curIndex = 0;

    for (auto regisFeature : _featuresVec) {
        curIndex++;
        MFloat confidenceLevel = 0;



        MRESULT pairRes = _imageFaceEngine.FacePairMatching(confidenceLevel, _curStaticImageFeature, regisFeature);
        if (MOK == pairRes && confidenceLevel > maxThreshold) {
            maxThreshold = confidenceLevel;
            maxIndex = curIndex;
        }
    }
    printf("%d:%.4f\n", maxIndex, maxThreshold);
}

bool FPM_Server::createHttpServer() {
    //#[ operation createHttpServer()
    _httpService = std::make_shared<HttpService>(_store);
    _httpServer = std::make_shared<HttpServer>(_httpService);

    if (!_httpServer->Listen()) {
        S_LOG_FATAL("Failed to createHttpServer.");
        cleanupObjects();
        return false;
    } else {
        // _httpServer->AddFilePath(Config::getInstance()->_picInfo.getPicDir());
        _httpServer->InitHandle();
    }
    S_LOG_DEBUG("createHttpServer success.");
    return true;
    //#]
}

bool FPM_Server::init() {
    //#[ operation init()
    _curStaticImageFeature.featureSize = FACE_FEATURE_SIZE;
    _curStaticImageFeature.feature = (MByte *) malloc(_curStaticImageFeature.featureSize * sizeof(MByte));
    return true;
    //#]
}

bool FPM_Server::run() {
    //#[ operation run()
    if (_running) return false;

    if (!Config::getInstance()->init()) {
        cleanupObjects();
        return false;
    }

    if (!createDatabaseStore()) {
        return false;
    }

    if (!createFPM()) {
        return false;
    }

    if (!createHttpServer()) {
        return false;
    }

    _running = true;
    return true;
    //#]
}

void FPM_Server::shutDown() {
    //#[ operation shutDown()
    if (_httpServer)
        _httpServer->Stop();

//    if (_fsw)
//        _fsw->stop();

    cleanupObjects();
    //#]
}

/*********************************************************************
	File Path	: ../../server/iLPR_Server.cpp
*********************************************************************/
